

#ifndef RTTRANSPORTTCP_H
#define RTTRANSPORTTCP_H

#include "RtTransportBase.h"
#include "RtSocket.h"

CRtString RtGetSystemErrorInfo(int inErrno);

class /*RT_API_EXPORT*/ CRtTransportTcp : public CRtTransportBase 
{
public:
	CRtTransportTcp(IRtReactor *pReactor);
	virtual ~CRtTransportTcp();

	// interface IRtEventHandler
	virtual RT_HANDLE GetHandle() const ;
	virtual int OnInput(RT_HANDLE aFd = RT_INVALID_HANDLE);
	virtual int OnOutput(RT_HANDLE aFd = RT_INVALID_HANDLE);

	// interface IRtTransport
	virtual RtResult SendData(
		CRtMessageBlock& inData,
		BOOL inSendImmediately = TRUE,
		BOOL inDestroyData = FALSE,
		DataPriority inPriority = DP_MEDIUM, 
		BOOL inNeedAck = TRUE);
	virtual RtResult SetOption(DWORD aCommand, LPVOID aArg);
	virtual RtResult GetOption(DWORD aCommand, LPVOID aArg);

	CRtSocketStream& GetPeer();

protected:
	virtual RtResult Open_t();
	virtual RtResult Close_t(RtResult aReason);

	int Recv_i(LPSTR aBuf, DWORD aLen);
	int Send_i(LPCSTR aBuf, DWORD aLen);

protected:
	CRtSocketStream m_socketTcp;
	BOOL m_needOnSend;
	CRtInetAddr m_peerAddrInProxyCase;
};


// inline functions
inline int CRtTransportTcp::Recv_i(LPSTR aBuf, DWORD aLen)
{
	// the recv len must be as large as possible
	// due to avoid lossing real-time signal
	RT_ASSERTE(aBuf && aLen > 0);
	int nRecv = m_socketTcp.Recv(aBuf, aLen);

	if (nRecv < 0) {
		if (errno == EWOULDBLOCK)
			return -2;
		else {
			CRtErrnoGuard egTmp;
			RT_WARNING_TRACE_THIS("CRtTransportTcp::Recv_i, recv() failed!"
				" fd=" << m_socketTcp.GetHandle() << 
				" err=" << RtGetSystemErrorInfo(errno));
			return -1;
		}
	}
	if (nRecv == 0) {
		RT_WARNING_TRACE_THIS("CRtTransportTcp::Recv_i, recv() 0! fd=" << m_socketTcp.GetHandle());
		// it is a graceful disconnect
		return -1;
	}
	return nRecv;
}

inline int CRtTransportTcp::Send_i(LPCSTR aBuf, DWORD aLen)
{
	RT_ASSERTE(aBuf && aLen > 0);
	int nSend = m_socketTcp.Send(aBuf, aLen);
	
	if (nSend < 0) {
		if (errno == EWOULDBLOCK)
			return 0;
		else {
			CRtErrnoGuard egTmp;
			RT_WARNING_TRACE_THIS("CRtTransportTcp::Send_i, send() failed!"
				" fd=" << m_socketTcp.GetHandle() << 
				" err=" << RtGetSystemErrorInfo(errno));
			return -1;
		}
	}
	return nSend;
}

#endif // !RTTRANSPORTTCP_H
